package com.yonyou.pmclouds.basecom.lock;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

@Aspect
@Component
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AutoReleaseLockManageAspect {
    private final static Object stackObj = new Object();
    private static ThreadLocal<List<String>> threadLockInfo = new ThreadLocal<List<String>>() {
        @Override
        protected List<String> initialValue() {
            return new ArrayList<>();
        }
    };
    private static ThreadLocal<Stack<Object>> threadStatckInfo = new ThreadLocal<Stack<Object>>() {
        @Override
        protected Stack<Object> initialValue() {
            return new Stack<>();
        }
    };

    static void addLockInfo(String key) {
        threadLockInfo.get().add(key);
    }

    @Around("execution(* com.yonyou.pmclouds..impl.*.*(..))||execution(* com.yonyou.pmclouds..rmiimpl.*.*(..))")
    public Object invoke(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        try {
            threadStatckInfo.get().push(stackObj);
            return proceedingJoinPoint.proceed();
        } finally {
            threadStatckInfo.get().pop();
            if (threadStatckInfo.get().empty()) {
                // 释放锁🔒
                List<String> lockKeys = threadLockInfo.get();
                try {
                    for (String lockKey : lockKeys) {
                        try {
                            PMLock.releaseLock(lockKey);
                        } catch (Exception e) {
                            // 由于🔒锁默认有超时，所以这里吃掉所有释放锁相关的异常，不去影响业务的处理
                            log.error("锁释放出现异常", e);
                        }
                    }
                } finally {
                    // 一次调用结束之后，清除所有的锁
                    threadLockInfo.get().clear();
                }
            }
        }
    }

}
